#include "App_BT.h"

static int BT_Init_Config(Device_t *device)
{
    // 初始化串口 9600 阻塞
    App_Serial_Init(device);

    // 修改串口为非阻塞
    App_Serial_SetBlock(device, 0);
    App_Serial_Flush(device);

    // 判断蓝牙是否可用，如果可用，说明蓝牙波特率是9600，修改波特率/名称/NETID/MADDR,重启蓝牙
    if (App_BT_Status(device) == 0)
    {
        // 表示已经连接
        App_BT_SetBaudBate(device, BT_BR_115200);
        App_BT_SetName(device, "ZY_BT");
        App_BT_SetNetId(device, "1234");
        App_BT_SetMaddr(device, "0101");
        App_BT_Restart(device);
        // 等待设备重启
        sleep(2);
    }

    // 走到这里已经将蓝牙的波特率修改为115200，而串口是9600，所以需要修改串口波特率为115200
    App_Serial_SetBaudRate(device, BR_115200);
    App_Serial_Flush(device);

    // 再次判断蓝牙是否可用，如果不可用，错误退出，蓝牙初始化失败
    if (App_BT_Status(device))
    {
        log_error("蓝牙初始化失败");
        return -1;
    }

    // 将串口改为阻塞模式
    App_Serial_SetBlock(device, 1);
    App_Serial_Flush(device);

    log_debug("蓝牙初始化成功");

    return 0;
}

int App_BT_Init(Device_t *device)
{
    // 1.将蓝牙的读后处理函数和写前函数传递给设备
    device->post_read = App_BT_PostRead;
    device->pre_write = App_BT_PreWrite;

    // 2.蓝牙初始化
    return 0;
}

/*
 接收方得到数据（3 + [2]）：f1 dd 07 23 23 ff ff 41 42 43
    f1 dd : 固定的头部
    07： 之后数据的长度（5-16之间）
    23 23：对端（发送方）的MADDR
    ff ff: 我的MADDR或ffff(群发)
    41 42 43：发送的数据
处理后的数据格式：conn_type id_len msg_len id msg

1. 缓存所有读取到的数据
2. 检查已缓存的数据里有没有一份完整的蓝牙数据
3. 如果还没有返回0, 继续读取处理
4. 如果有， 根据它生成字符数组，保存到data中，并返回数据长度
*/
static char read_buff[1024]; // 用来缓存读取的蓝牙数据
static int read_len = 0;     // 已缓存的数据长度
static char fix_header[2] = {0xf1, 0xDD};

static void remove_data(int num)
{
    // read_len - num是需要保留数据的长度
    memmove(read_buff, read_buff + num, read_len - num);
    read_len -= num;
}
int App_BT_PostRead(char *data, int datalen)
{
    // 缓存当前读到的数据
    memcpy(read_buff + read_len, data, datalen);
    // 更新已缓存的数据长度
    read_len += datalen;

    // 如果已缓存数据长度小于8,说明数据不完整，返回0继续读取
    if (read_len < 8)
    {
        log_debug("蓝牙数据不完整，重新读取");
        return 0;
    }

    // 遍历read_buff 检查已缓存的数据有没有完整的蓝牙数据
    for (int i = 0; i < read_len - 7; i++)
    {
        if (memcmp(fix_header, read_buff + i, 2) == 0)
        {
            // f1 dd 07 23 23 ff ff 41 42 43
            if (i > 0)
            {
                // 删除前面无用的数据
                remove_data(i);
            }
            // 完整的蓝牙数据长度
            int blue_len = 3 + read_buff[2];
            // 如果缓存数据的长度小于完整的蓝牙数据长度，说明数据不完整，返回0，继续读取
            if (read_len < blue_len)
            {
                log_debug("蓝牙数据不完整，继续读取");
                return 0;
            }
            // 走到这说明至少读取了一次完整的蓝牙数据
            // 根据缓存的完整蓝牙数据生成字符数组保存到data中
            // 缓存完数据后先清空data
            memset(data, 0, datalen);
            // conn_type id_len msg_len id msg
            data[0] = 1;                                  // conn_type
            data[1] = 2;                                  // id_len
            data[2] = read_buff[2] - 4;                   // msg_len(4指的是固定长度的发送方地址和本机地址，read_buff[2]存的是之后数据的长度（5-16之间）)
            memcpy(data + 3, read_buff + 3, 2);           // id
            memcpy(data + 3 + 2, read_buff + 7, data[2]); // msg

            // 保存完数据后删除已处理的蓝牙数据，方便下次读取数据
            remove_data(blue_len);
            // 返回字符数据的长度
            return 3 + 2 + data[2]; // 3+id_len+msg_len
        }
        // 走到这里说明没有遍历到标识符，遍历的数据全是无效数据
        if (i > 0)
        {
            // 删除遍历的无效数据
            remove_data(i);
        }
    }

    return 0;
}

/*
字符数组消息:
    例子：1 2 3 XX abc
    格式：conn_type id_len msg_len id msg
蓝牙发送数据格式例子：
    例子：41 54 2b 4d 45 53 48 00 ff ff 61 62 63 0d 0a
    41 54 2b 4d 45 53 48 00： AT+MESH（固定头部）
    ff ff: 对端的MADDR（如果是FFFF代表群发）
    61 62 63: 要发送的数据（不超过12字节）
    0d 0a：\r\n（固定结尾）
    AT+MESH XX abc \r\n
*/

int App_BT_PreWrite(char *data, int datalen)
{
    // 检查字符数组
    if (datalen < 6)
    {
        log_error("字符数组消息长度不够");
        return -1;
    }
    // 计算蓝牙数据长度
    int blue_len = 12 + data[2]; // data[2]表示要发送的数据长度，12是固定长度
    // 创建蓝牙数据数组
    char blue_data[blue_len];

    // 向蓝牙数组存放蓝牙数据的各个部分
    // AT+MESH
    memcpy(blue_data, "AT+MESH", 8); // 包含结束符
    // id
    memcpy(blue_data + 8, data + 3, 2);
    // msg
    memcpy(blue_data + 10, data + 5, data[2]);
    // \r\n
    memcpy(blue_data + 10 + data[2], "\r\n", 2);

    // 储存完后清空data
    memset(data, 0, datalen);
    // 将blue_data拷贝到data中
    memcpy(data, blue_data, blue_len);
    // 返回蓝牙数据长度
    return blue_len;
}

int App_Wait_Ack(int fd)
{
    // 等待一定的时间（50ms）
    usleep(50 * 1000);

    // 从串口文件中读取4个字节的数据，判断是否是OK\r\n
    char data_buff[4];
    read(fd, data_buff, 4);
    if (memcmp(data_buff, "OK\r\n", 4) != 0)
    {
        log_error("等待ACK超时");
        return -1;
    }
    return 0;
}

// 判断蓝牙连接状态
int App_BT_Status(Device_t *device)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char *cmd = "AT\r\n";
    write(device->fd, cmd, strlen(cmd));
    // 等待ACK
    return Wait_Ack(device->fd);
}

// 修改蓝牙名称
int BT_SetName(Device_t *device, char *name)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+NAME%s\r\n", name);
    write(device->fd, cmd, strlen(cmd));

    // 等待ACK
    return Wait_Ack(device->fd);
}

// 修改蓝牙波特率
int App_BT_SetBaudBate(Device_t *device, BT_BR baudRate)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+BAUD%d\r\n", baudRate);
    write(device->fd, cmd, strlen(cmd));

    // 等待ACK
    return Wait_Ack(device->fd);
}

// 重启蓝牙模块
int App_BT_Restart(Device_t *device)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char *cmd = "AT+RESET\r\n";
    write(device->fd, cmd, strlen(cmd));

    // 等待ACK
    return Wait_Ack(device->fd);
}

// 设置蓝牙的组网ID
int App_BT_SetNetId(Device_t *device, char *netId)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+NETID%s\r\n", netId);
    write(device->fd, cmd, strlen(cmd));
    // 等待ACK
    return Wait_Ack(device->fd);
}

// 设置蓝牙的MAC地址
int App_BT_SetMaddr(Device_t *device, char *maddr)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+MADDR%s\r\n", maddr);
    write(device->fd, cmd, strlen(cmd));
    // 等待ACK
    return Wait_Ack(device->fd);
}
